package xiaopiya.robot.threads;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * @author Ray (ayufox@gmail.com)
 *
 */
public class ThreadpoolExecutorFactoryBean implements FactoryBean,
		InitializingBean, DisposableBean
{
	private final static Log LOG = LogFactory
			.getLog(ThreadpoolExecutorFactoryBean.class);

	/*
	 * corePoolSize the number of threads to keep in the
	 * pool, even if they are idle.
	 */
	private int corePoolSize = 10; //线程池中保持的最少线程数

	/*
	 * maximumPoolSize the maximum number of threads to allow in the
	 * pool.
	 */
	private int maxPoolSize = Integer.MAX_VALUE; //线程池中保持的最大线程数

	/*
	 * keepAliveTime when the number of threads is greater than
	 * the core, this is the maximum time that excess idle threads
	 * will wait for new tasks before terminating.
	 */
	private int keepAliveSeconds = 5 * 60;

	/*
	 * 等待队列的最大容量
	 */
	private int queueCapacity = Integer.MAX_VALUE;

	/*
	 * 停止时等待线程池关闭时间 
	 */
	private int threadPoolAwaitTimeSeconds = 10;

	private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();

	private ThreadFactory threadFactory = Executors.defaultThreadFactory();

	public void setCorePoolSize(int corePoolSize)
	{
		if (corePoolSize < 0)
		{
			throw new IllegalArgumentException(
					"corePoolSize must not less than zero");
		}
		this.corePoolSize = corePoolSize;
	}

	public void setMaxPoolSize(int maxPoolSize)
	{
		if (maxPoolSize < 1)
		{
			throw new IllegalArgumentException(
					"maxPoolSize must not less greater than one");
		}
		this.maxPoolSize = maxPoolSize;
	}

	public void setKeepAliveSeconds(int keepAliveSeconds)
	{
		if (keepAliveSeconds < 1)
		{
			throw new IllegalArgumentException(
					"keepAliveSeconds must not less greater than one");
		}
		this.keepAliveSeconds = keepAliveSeconds;
	}

	public void setQueueCapacity(int queueCapacity)
	{
		if (queueCapacity < 1)
		{
			throw new IllegalArgumentException(
					"queueCapacity must not less greater than one");
		}
		this.queueCapacity = queueCapacity;
	}

	public void setThreadPoolAwaitTimeSeconds(int threadPoolAwaitTimeSeconds)
	{
		this.threadPoolAwaitTimeSeconds = threadPoolAwaitTimeSeconds;
	}

	public void setRejectedExecutionHandler(
			RejectedExecutionHandler rejectedExecutionHandler)
	{
		if (rejectedExecutionHandler == null)
		{
			throw new IllegalArgumentException(
					"rejectedExecutionHandler can't be null");
		}
		this.rejectedExecutionHandler = rejectedExecutionHandler;
	}

	public void setThreadFactory(ThreadFactory threadFactory)
	{
		if (threadFactory == null)
		{
			throw new IllegalArgumentException("threadFactory can't be null");
		}
		this.threadFactory = threadFactory;
	}

	private ThreadPoolExecutor threadPoolExecutor = null;

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception
	{
		this.threadPoolExecutor = new ThreadPoolExecutor(this.corePoolSize,
				this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
				new LinkedBlockingQueue(this.queueCapacity),
				this.threadFactory, this.rejectedExecutionHandler);

		if (LOG.isInfoEnabled())
		{
			LOG.info("create Thread Pool[corePoolSize=" + this.corePoolSize
					+ ",maxPoolSize=" + this.maxPoolSize + ",keepAliveSeconds="
					+ this.keepAliveSeconds + ",queueCapacity"
					+ this.queueCapacity + "]");
		}
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	public Object getObject() throws Exception
	{
		return this.threadPoolExecutor;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#getObjectType()
	 */
	public Class getObjectType()
	{
		return ThreadPoolExecutor.class;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#isSingleton()
	 */
	public boolean isSingleton()
	{
		return true;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.DisposableBean#destroy()
	 */
	public void destroy() throws Exception
	{
		if (this.threadPoolExecutor != null)
		{
			try
			{
				LOG.info("await thread pool Termination");
				threadPoolExecutor.awaitTermination(
						this.threadPoolAwaitTimeSeconds, TimeUnit.SECONDS);
			} catch (InterruptedException e)
			{
				LOG.error("Error when awaitTermination", e);
			}
		}
	}
}
